﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using TransportLayer.NodeToolsLibrary;


namespace TransportLayer.NodeLibrary
{
    public class NodeSNP : Cleaner
    {


        // Referencja switcha zarzadzanego przez agenta
        private Node node;
        // Zawartosc konfiguracji wezla
        
        private Socket managerSocket;
        private byte[] buffer = new byte[4086];

        /*Constructor 
         *
         *
         */ 
        public NodeSNP(Node n, int port) 
        {
            node = n;
            try
            {
                managerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint server = new IPEndPoint(IPAddress.Loopback, port);
                managerSocket.Connect(server);
                managerSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, managerSocket);
            }
            catch (SocketException ex) { }
        }


        public void Send(string message)
        {
            byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
            managerSocket.Send(data);
        }
       private void OnDataReceived(IAsyncResult asyn)
        {
            
            int recv;
            try { recv = managerSocket.EndReceive(asyn); }
            catch (SocketException) { managerSocket.Close(); return; }
            if (recv == 0)
            {
                managerSocket.Close();
                return;
            }
            string query = Encoding.ASCII.GetString(buffer, 0, recv);
            //prepere response
            string response = ProcessQuery(query);
            if (response != "")
                managerSocket.Send(System.Text.Encoding.ASCII.GetBytes(response));
                managerSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, managerSocket);
        }

       public string ProcessQuery(string query)
       {
           query = query.ToLower();
           string[] command = query.Split(' ');
           string response = "";
           if (command[0] == "ping")
           {
               response += "ping";
           }
           else if (command[0] == "get")
           {
               if (command.Length == 3 && command[1] == "log")
               {
                   int n;
                   try { n = Int32.Parse(command[2]); }
                   catch (FormatException) { n = 0; }
                   if (n == 0)
                       return Serial.SerializeObject(node.Log);
                   else
                       return Serial.SerializeObject(new Log(node.Log, n));
               }
               if (command.Length != 2)
                   return "getresp";
               if (command[1] == "routing")
                   return "getresp " + node.Sfm.ToString(); ;
               response += "getresp " + command[1];
               string[] param = command[1].Split('.');
               if (param[0] == "type")
                   response += " Node";
               else if (param[0] == "id")
                   response += " " + node.Id;
               else if (param[0] == "name")
                   response += " " + node.Name;
               else if (param[0] == "portsin")
               {
                   if (param.Length != 3 && param.Length != 5)
                       return response;
                   int n;
                   try { n = Int32.Parse(param[1]); }
                   catch (FormatException) { return response; }
                   if (n >= node.PortsIn.Length)
                       return response;
                   if (param[2] == "open")
                       response += " " + node.PortsIn[n].Open;
                   else if (param[2] == "connected")
                       response += " " + node.PortsIn[n].Connected;
                   else if (param[2] == "_port")
                       response += " " + node.PortsIn[n].TcpPort;
                   else if (param[2] == "available")
                   {
                           response += " " + node.DownPortIn();  
                   }
               }
               else if (param[0] == "portsout")
               {
                   if (param.Length != 3 && param.Length != 5)
                       return response;
                   int n;
                   try { n = Int32.Parse(param[1]); }
                   catch (FormatException) { return response; }
                   if (n >= node.PortsOut.Length)
                       return response;
                   if (param[2] == "open")
                       response += " " + node.PortsOut[n].Open;
                   else if (param[2] == "connected")
                       response += " " + node.PortsOut[n].Connected;
                   else if (param[2] == "_port")
                       response += " " + node.PortsOut[n].TcpPort;
                   else if (param[2] == "available")
                   {
                       response += node.DownPortOut();
                   }
               }
           }
           else if (command[0] == "set")
           {
               if (command.Length != 3)
                   return "setresp";
               response += "setresp " + command[1];
               string[] param = command[1].Split('.');
               if (param[0] == "id")
                   response += " " + node.Id; // parametr niezmienny
               else if (param[0] == "name")
               {
                   node.Name = command[2];
                   response += " " + node.Name;
               }
               else if (param[0] == "portsin")
               {
                   if (param.Length != 3)
                       return response;
                   int n;
                   try { n = Int32.Parse(param[1]); }
                   catch (FormatException) { return response; }
                   if (n >= node.PortsIn.Length)
                       return response;
                   if (param[2] == "open")
                       response += " " + node.PortsIn[n].Open; // póki co niezmienne
                   else if (param[2] == "connected")
                       response += " " + node.PortsIn[n].Connected; // niezmienne
                   else if (param[2] == "_port")
                       response += " " + node.PortsIn[n].TcpPort; // niezmienne

                   node.Log.LogMsg(response);
               }
               else if (param[0] == "portsout")
               {
                   if (param.Length != 3)
                       return response;
                   int n;
                   try { n = Int32.Parse(param[1]); }
                   catch (FormatException) { return response; }
                   if (n >= node.PortsOut.Length)
                       return response;
                   if (param[2] == "open")
                       response += " " + node.PortsOut[n].Open; // póki co niezmienne
                   else if (param[2] == "connected")
                   {
                       if (command[2] == "true")
                           node.PortsOut[n].Connect();
                           response += " " + node.PortsOut[n].Connected;
                   }
                   else if (param[2] == "_port")
                   {
                       try
                       {
                           node.PortsOut[n].TcpPort = Int32.Parse(command[2]);
                       }
                       catch (FormatException) { return response; }
                       response += " " + node.PortsOut[n].TcpPort;
                   }
               }
               node.Log.LogMsg(response);
           }
           else if (command[0] == "rtadd")
           {
               response += "rtaddresp ";
               if (command.Length == 3)
               {
                   if (node.Sfm.Add(command[1], command[2]))
                       response += "ok";
                   else response += "fail";
               }
               else response += "fail";  
               node.Log.LogMsg(response);
           }
           else if (command[0] == "rtdel")
           {
               response += "rtdelresp ";
               try
               {
                   int connectionID = Int32.Parse(command[1]);
                   if (node.Sfm.Remove(connectionID))
                       response += "true";
                   else response += "false";

                       node.Log.LogMsg(response);
               }
               catch (FormatException)
               {
                   response += "false";
               }
           }
           else
               response = command[0] + "resp";
           return response;
       }

       public void Clean()
       {
           managerSocket.Close();
       
       }
    
    }
}
